package com.itcast.common.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jzo2o.common.expcetions.ServerErrorException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Map;

/**
 * rest请求工具类
 * 针对http调用云岚到家服务的工具类
 *
 * @author itcast
 * @create 2024/5/15 11:38
 **/
@Slf4j
@Component
public class RestTemplateUtils {
    @Resource
    private RestTemplate restTemplate;

    /**
     * 发起http请求并获取响应结果。
     *
     * @param url 请求的URL地址。
     * @return 返回从指定URL获取的响应数据。
     * @throws ServerErrorException 当请求发送失败或响应状态码不是200时抛出。
     */
    public String get(String url) {
        // 设置请求头
        HttpHeaders httpHeaders = new HttpHeaders();
        HttpEntity<Object> httpEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity<String> response;
        try {
            // 发起http请求
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        } catch (Exception e) {
            // 记录请求发送失败的日志
            log.error("http请求发送失败,请求路径：{}，异常信息-->", url, e);
            throw new ServerErrorException("http请求发送失败");
        }

        return parseResponse(url, response);
    }

    /**
     * 使用GET方法发送HTTP请求。
     *
     * @param url        请求的URL地址。
     * @param parameters 请求的参数，以对象形式传递。
     * @return 返回处理后的HTTP响应。
     * @throws ServerErrorException 当HTTP请求发送失败时抛出此异常。
     */
    public String get(String url, Object parameters) {
        // 将参数对象转换为Map，以便处理参数拼接。
        Map<String, Object> parameterMap = BeanUtil.beanToMap(parameters, false, true);

        return get(url, parameterMap);
    }

    /**
     * 使用GET方法发送HTTP请求。
     *
     * @param url          请求的URL地址。
     * @param parameterMap 请求的参数，map格式。
     * @return 返回处理后的HTTP响应。
     */
    public String get(String url, Map<String, Object> parameterMap) {
        // 构建带有参数的URL字符串。
        StringBuilder urlBuilder = new StringBuilder(url);
        for (Map.Entry<String, Object> entry : parameterMap.entrySet()) {
            urlBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }
        url = urlBuilder.toString();

        // 初始化HTTP请求实体。
        HttpEntity<Object> httpEntity = new HttpEntity<>(new HttpHeaders());
        ResponseEntity<String> response;
        try {
            // 发起HTTP GET请求。
            // 发起http请求
            response = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class);
        } catch (Exception e) {
            // 记录HTTP请求发送失败的日志。
            // 记录请求发送失败的日志
            log.error("http请求发送失败,请求路径：{}，异常信息-->", url, e);
            // 抛出自定义异常，表示HTTP请求发送失败。
            throw new ServerErrorException("http请求发送失败");
        }

        // 解析HTTP响应并返回。
        return parseResponse(url, response);
    }

    /**
     * 向指定URL发送POST请求，并返回处理后的响应。
     *
     * @param url         请求的URL地址
     * @param requestBody 请求体中的参数，以Map形式提供
     * @return 处理后的响应内容
     * @throws ServerErrorException 当HTTP请求发送失败时抛出
     */
    public String post(String url, Map<String, Object> requestBody) {
        // 初始化HTTP请求头，设置内容类型为JSON
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);

        // 构建请求实体，包括请求体和请求头
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, httpHeaders);

        ResponseEntity<String> response;
        try {
            // 发送POST请求，并获取响应实体
            response = restTemplate.postForEntity(url, requestEntity, String.class);
        } catch (Exception e) {
            log.error("http请求发送失败,请求路径：{}，异常信息-->", url, e);
            throw new ServerErrorException("http请求发送失败");
        }

        // 解析响应，并返回处理后的结果
        return parseResponse(url, response);
    }

    /**
     * 向指定URL发送POST请求，并返回处理后的响应。
     *
     * @param url         请求的URL地址
     * @param requestBody 请求体中的对象
     * @return 处理后的响应内容
     */
    public String post(String url, Object requestBody) {
        // 初始化HTTP请求头，设置内容类型为JSON
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);

        // 构建请求实体
        HttpEntity<Object> requestEntity = new HttpEntity<>(requestBody, httpHeaders);

        ResponseEntity<String> response;
        try {
            // 发送POST请求，并获取响应
            response = restTemplate.postForEntity(url, requestEntity, String.class);
        } catch (Exception e) {
            log.error("http请求发送失败,请求路径：{}，异常信息-->", url, e);
            throw new ServerErrorException("http请求发送失败");
        }

        // 处理并返回响应
        return parseResponse(url, response);
    }

    /**
     * 发送无需认证的POST请求
     *
     * @param url 请求的URL地址
     * @return 响应结果处理后的字符串
     */
    public String post(String url) {
        // 初始化HTTP请求头，设置内容类型为JSON
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.APPLICATION_JSON);

        // 构建包括请求头的请求实体
        HttpEntity<Map<String, String>> requestEntity = new HttpEntity<>(httpHeaders);

        ResponseEntity<String> response;
        try {
            // 发送POST请求，并获取响应实体
            response = restTemplate.postForEntity(url, requestEntity, String.class);
        } catch (Exception e) {
            log.error("http请求发送失败,请求路径：{}，异常信息-->", url, e);
            throw new ServerErrorException("http请求发送失败");
        }

        // 解析响应，并返回处理后的结果
        return parseResponse(url, response);
    }

    /**
     * 解析响应结果
     *
     * @param url      请求地址
     * @param response 响应结果
     * @return 响应体
     */
    private String parseResponse(String url, ResponseEntity<String> response) {
        // 检查响应状态码
        if (!response.getStatusCode().equals(HttpStatus.OK)) {
            log.error("http请求响应失败,请求路径：{}，响应信息:{}", url, response);
            throw new ServerErrorException("http请求响应失败");
        }

        //解析响应体，判断是否存在code字段。如果不存在，body即是响应结果；否则就是还有一层响应包装，需要拆解
        JSONObject responseBody = JSONUtil.parseObj(response.getBody());
        if (ObjectUtil.isEmpty(responseBody.get("code"))) {
            return response.getBody();
        }

        if (!responseBody.get("code").equals(HttpStatus.OK.value())) {
            log.error("http请求响应失败,请求路径：{}，响应信息:{}", url, response);
            if (ObjectUtil.isNotEmpty(responseBody.get("message"))) {
                throw new ServerErrorException(responseBody.get("message").toString());
            }
            throw new ServerErrorException("http请求响应失败");
        }

        Object responseData = responseBody.get("result");
        return ObjectUtil.isEmpty(responseData) ? null : responseData.toString();
    }
}
